package org.samcolon.spring_security.demo1;

import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;

import javax.sql.DataSource;
import javax.annotation.Resource;

/**
 * @Description:
 * @author: Sam.zhang
 * @date: 2022/2/9 - 1:23
 * Security 配制
 */
@EnableWebSecurity
@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {


    /**
     * 处理http请求的配制，网页接口级别
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 类识xml
        // 父标签
        http
                .authorizeRequests()// 认证http请求
//                .antMatchers("/test/**").permitAll()
//                .anyRequest().permitAll()
                .anyRequest()
                .authenticated()// 所有的请求都去认证
                // 子标签及相关属性
                // and可以返回http对象
                .and()


                .formLogin() // 登录表单
                .loginPage("/login.html") // 登录页面配制
//                .permitAll() // 不进行认证，允许所有
                .loginProcessingUrl("/login").permitAll() // 登录接口配制

                .failureUrl("/login.html?error") // 登录失败后跳转接口
                .defaultSuccessUrl("/index", true).permitAll() // 登录成功后转发
                // 登录失败后的处理器
                .failureHandler((request, response, exception) -> {
                    exception.printStackTrace();
                    request.getRequestDispatcher(request.getRequestURL().toString()).forward(request, response);
                })


                .and()
                // 设置防csrf攻击
                .csrf()
//                .disable() //默认是开启的 关闭
                // 有多种实现方式，HttpSessionCsrfTokenRepository只是其中一种
                // HttpSessionCsrfTokenRepository
                // CookieCsrfTokenRepository
                // LazyCsrfTokenRepository
                // TestCsrfTokenRepository
                .csrfTokenRepository(new HttpSessionCsrfTokenRepository())

//                .and()
        ;
    }

    /**
     * 定义密码加密的方式
     *
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
//        测试时使用，此方法，没有做任何操作
//        return NoOpPasswordEncoder.getInstance();
        // 正常情况下，使用此方法
        return new BCryptPasswordEncoder();
    }


    @Resource
    DataSource dataSource;
    /**
     * 登录实现及用户注册
     * 配制后，application配制文件中的用户名密码配制，就会失效
     *
     * @return
     */
//    @Bean
//    public UserDetailsService userDetailsService(){
//
//        // 基于内存存储用户，用户信息存放于内存
////        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
////        // 自定义必须实现 UserDetailsManager
//////      重要：使用用户名查找用户
//////        manager.loadUserByUsername(username)
////
//////        manager.createUser();
//////        manager.deleteUser();
//////        manager.updateUser();
//////        manager.changePassword();
//////        manager.userExists()
////
////        // spring security框架中的user
////        // user实现了UserDetails
////        User user = new User("a",
////                new BCryptPasswordEncoder().encode("1"),
////                true,
////                true,
////                true,
////                true,
////                CollUtil.newArrayList(new SimpleGrantedAuthority("admin")));
////
////        manager.createUser(user);
////        // 手动创建时，一定要给角色，同时必须要build
////        manager.createUser(
////                User.withUsername("zhangchao")
////                        .password(new BCryptPasswordEncoder().encode("1")).roles("admin").build());
//
//        JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
//
//        manager.createUser(
//                User.withUsername("zhangchao")
//                        .password(new BCryptPasswordEncoder().encode("1")).roles("admin").build());
//
//        return manager;
//    }


    /**
     * 处理所有和权限相关的
     * 此方法只会执行一次，在启动项目时，运行
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.inMemoryAuthentication()
//                .withUser("123").password(new BCryptPasswordEncoder().encode("123")).roles("admin")
//                .and()
//                .withUser("321").password("321").roles("admin")
//
//                ;
        // 自定义ORM
        auth.userDetailsService(new MyUserDetailsService())

                .and()
                // 权限效验提供者
                // 提供自定义的权限效验器
                .authenticationProvider(new MyAuthProvider());
        // 注册用户
//        JdbcUserDetailsManager manager = auth.jdbcAuthentication().dataSource(dataSource).getUserDetailsService();
//        if(manager.userExists("sam")) {
//            manager.createUser(
//                    User.withUsername("sam")
//                            .password(new BCryptPasswordEncoder().encode("1")).roles("admin").build());
//        }


    }


    /**
     * 处理所有网络相关的配制，更加的底层
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/img/**");
//        super.configure(web);
    }


}
